﻿using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using SmartPlant.Model;
using SmartPlant.WinCore;
using SmartPlant.WinCore.Exceptions;
using SmartPlant.WinCore.Helper;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace SmartPlant.Services
{
    /// <summary>
    /// 所有远程服务基类，提供HTTP Get、POST等通用封装。
    /// <see cref="HttpResponseMessage.StatusCode"/>是http级别的信息码。所以原则上，server不管怎么样，都是返回200的信息码
    /// <see cref="RESTfulResult.code"/>或者<see cref="RESTfulResult.succeeded"/>是furion框架内的状态码。
    /// </summary>
    public abstract class BaseService
    {
        /// <summary>
        /// 请求超时时间。
        /// </summary>
        private int timeOut = 200;
        private string _authorizationCode = string.Empty;
        protected string AuthorizationCode
        {
            get
            {
                if (_authorizationCode.IsNotEmptyOrNull()) return _authorizationCode;
                _authorizationCode = GlobalObject.AuthorizationCode;
                return _authorizationCode;
            }
            private set
            {
                _authorizationCode = value;
            }
        }

        protected string ServerUrl { get; set; }

        public BaseService()
        {
            AuthorizationCode = GlobalObject.AuthorizationCode;
            ServerUrl = GlobalObject.CurrentConfig.ServerAddress;
            timeOut = GlobalObject.CurrentConfig.ConnectionTimeOut;
        }

        #region Init Header

        /// <summary>
        /// 带入授权码。
        /// </summary>
        /// <param name="httpClient"></param>
        protected virtual void OnInitAuthorizationCode(HttpClient httpClient)
        {
            httpClient.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows 10.0.22621.1265; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/110.0.835.163 Safari/535.1");

            if (AuthorizationCode.IsNullOrEmpty() || httpClient == null) return;
            httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + AuthorizationCode);
        }

        protected virtual void OnInitRequestHeader(HttpClient httpClient, string mediaType)
        {
            //httpClient.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue(mediaType));
            httpClient.DefaultRequestHeaders.Add("Accept", mediaType);
            httpClient.DefaultRequestHeaders.Add("ContentType", mediaType);
        }
        #endregion

        #region Get
        /// <summary>
        /// Get异步请求
        /// </summary>
        /// <typeparam name="T">对应server端，Get接口返回的数据格式</typeparam>
        /// <param name="requestUri"></param>
        /// <param name="paramObj"></param>
        /// <param name="getUrl"></param>
        /// <returns></returns>
        /// <exception cref="DataRequestException"></exception>
        protected async Task<RESTfulResult<T>> GetAsync<T>(string requestUri, object paramObj = null, Func<string> getUrl = null)
        {
            var url = GetHttpUrl(requestUri, paramObj, getUrl);
            using var client = HttpClientFactory.Create();
            client.Timeout = TimeSpan.FromSeconds(timeOut);
            OnInitAuthorizationCode(client);
            var response = await client.GetAsync(url);
            if (response.StatusCode != HttpStatusCode.OK)
            {
                string errorMsg = $"远程服务地址{requestUri}获取服务数据失败, 返回代码：" + response.StatusCode;
                LoggerHelper.Current.Error(errorMsg);
                throw new DataRequestException(errorMsg);
            }
            var result = await response.Content.ReadAsStringAsync();
            var resultObj = JsonConvert.DeserializeObject<RESTfulResult<T>>(result);
            if (!resultObj.succeeded)
            {
                switch (resultObj.statusCode)
                {
                    case 400:
                    case 500:
                        //errors里有内容
                        break;
                    default:
                        string errorMsg = $"远程服务地址{requestUri}获取服务数据失败：" + resultObj.errors;
                        LoggerHelper.Current.Error(errorMsg);
                        throw new DataRequestException(errorMsg);
                }

            }
            LoggerHelper.Current.Info($"获取服务数据成功：{url}");
            return resultObj;
        }

        /// <summary>
        /// Get异步请求（分页）
        /// </summary>
        /// <param name="resultType">分页数据里的List的具体类型</param>
        /// <param name="requestUri"></param>
        /// <param name="paramObj"></param>
        /// <returns>返回分页PageResult数据</returns>
        /// <exception cref="DataRequestException"></exception>
        protected async Task<PageResult<dynamic>> GetDynamicObjAsync(Type resultType, string requestUri, object paramObj = null)
        {
            var url = GetHttpUrl(requestUri, paramObj, null);
            using var client = HttpClientFactory.Create();
            client.Timeout = TimeSpan.FromSeconds(timeOut);
            OnInitAuthorizationCode(client);
            var response = await client.GetAsync(url);
            if (response.StatusCode != HttpStatusCode.OK)
            {
                string errorMsg = $"远程服务地址{requestUri}获取服务数据失败, 返回代码：" + response.StatusCode;
                LoggerHelper.Current.Error(errorMsg);
                throw new DataRequestException(errorMsg);
            }
            var result = await response.Content.ReadAsStringAsync();
            var strObjResult = JsonConvert.DeserializeObject<RESTfulResultPage<JArray>>(result);

            if (!strObjResult.succeeded)
            {
                string errorMsg = $"远程服务地址{requestUri}获取服务数据失败：" + strObjResult.errors;
                LoggerHelper.Current.Error(errorMsg);
                throw new DataRequestException(errorMsg);
            }
            var jsonStr = strObjResult.data.Data.Serialize();
            var dataObj = JsonConvert.DeserializeObject(jsonStr, resultType);

            var pageResult = new PageResult<dynamic>
            {
                Data = dataObj,
                Count = strObjResult.data.Count
            };
            LoggerHelper.Current.Info($"获取服务数据成功：{url}");
            return pageResult;
        }

        #endregion


        /// <summary>
        /// 普通的post请求（分页）
        /// </summary>
        /// <typeparam name="T">返回的类型</typeparam>
        /// <param name="requestUri"></param>
        /// <param name="paramObj"></param>
        /// <returns></returns>
        /// <exception cref="HttpRequestException"></exception>
        //protected async Task<PageResult<dynamic>> PostDynamicObjAsync<T>(Type resultType, string requestUri, T postObj, object paramObj = null)
        //{
        //    string contentType = "application/json";
        //    var url = GetHttpUrl(requestUri, paramObj, null);
        //    using var client = HttpClientFactory.Create();
        //    client.Timeout = TimeSpan.FromSeconds(timeOut);
        //    OnInitAuthorizationCode(client);

        //    string strContent = postObj != null ? JsonConvert.SerializeObject(postObj) : "";
        //    var content = new StringContent(strContent, Encoding.UTF8, contentType);

        //    var response = await client.PostAsync(url, content);
        //    if (response.StatusCode != HttpStatusCode.OK)
        //    {
        //        string errorMsg = $"远程服务地址{requestUri}获取服务数据失败, 返回代码：" + response.StatusCode;
        //        LoggerHelper.Current.Error(errorMsg);
        //        throw new DataRequestException(errorMsg);
        //    }
        //    var result = await response.Content.ReadAsStringAsync();
        //    var strObjResult = JsonConvert.DeserializeObject<RESTfulResultPage<JArray>>(result);

        //    if (!strObjResult.succeeded)
        //    {
        //        string errorMsg = $"远程服务地址{requestUri}获取服务数据失败：" + strObjResult.errors;
        //        LoggerHelper.Current.Error(errorMsg);
        //        throw new DataRequestException(errorMsg);
        //    }
        //    var jsonStr = strObjResult.data.Data.Serialize();
        //    var dataObj = JsonConvert.DeserializeObject(jsonStr, resultType);

        //    var pageResult = new PageResult<dynamic>
        //    {
        //        Data = dataObj,
        //        Count = strObjResult.data.Count
        //    };
        //    LoggerHelper.Current.Info($"获取服务数据成功：{url}");
        //    return pageResult;
        //}




        #region Put


        /// <summary>
        /// 向远程服务器Put数据，需要body里带上数据
        /// </summary>
        /// <typeparam name="T0">返回的类型</typeparam>
        /// <typeparam name="T1">body里数据的类型</typeparam>
        /// <param name="requestUri"></param>
        /// <param name="postObj"></param>
        /// <returns></returns>
        /// <exception cref="DataRequestException"></exception>
        protected async Task<RESTfulResult<T0>> PutBodyAsync<T0, T1>(string requestUri, T1 data)
        {
            string contentType = "application/json";
            var url = ServerUrl.CombineUrlPath(requestUri);

            string strContent = data != null ? JsonConvert.SerializeObject(data) : "";
            var content = new StringContent(strContent, Encoding.UTF8, contentType);

            using var client = HttpClientFactory.Create();
            client.Timeout = TimeSpan.FromSeconds(timeOut);
            OnInitAuthorizationCode(client);
            OnInitRequestHeader(client, contentType);
            var response = await client.PutAsync(url, content);
            if (response.StatusCode != HttpStatusCode.OK)
            {
                string errorMsg = $"远程服务地址{requestUri}发送服务数据失败, 返回代码：" + response.StatusCode;
                LoggerHelper.Current.Error(errorMsg);
                throw new DataRequestException(errorMsg);
            }
            response.EnsureSuccessStatusCode();
            string result = await response.Content.ReadAsStringAsync();

            var resultObj = JsonConvert.DeserializeObject<RESTfulResult<T0>>(result);
            if (!resultObj.succeeded)
            {
                string errorMsg = $"远程服务地址{requestUri}发送服务数据失败：" + resultObj.errors;
                LoggerHelper.Current.Error(errorMsg);
                throw new DataRequestException(errorMsg);
            }
            LoggerHelper.Current.Info($"发送服务数据成功：{url}");
            return resultObj;
        }

        /// <summary>
        /// 向远程服务器Put数据。不需要body
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="requestUri"></param>
        /// <param name="paramObj"></param>
        /// <param name="getUrl"></param>
        /// <returns></returns>
        /// <exception cref="DataRequestException"></exception>
        protected async Task<RESTfulResult<T>> PutAsync<T>(string requestUri, object paramObj = null, Func<string> getUrl = null)
        {
            var url = GetHttpUrl(requestUri, paramObj, getUrl);
            using var client = HttpClientFactory.Create();
            client.Timeout = TimeSpan.FromSeconds(timeOut);
            OnInitAuthorizationCode(client);
            var response = await client.PutAsync(url, null);
            if (response.StatusCode != HttpStatusCode.OK)
            {
                string errorMsg = $"远程服务地址{requestUri}获取服务数据失败, 返回代码：" + response.StatusCode;
                LoggerHelper.Current.Error(errorMsg);
                throw new DataRequestException(errorMsg);
            }
            var result = await response.Content.ReadAsStringAsync();
            var resultObj = JsonConvert.DeserializeObject<RESTfulResult<T>>(result);
            if (!resultObj.succeeded)
            {
                switch (resultObj.statusCode)
                {
                    case 400:
                    case 500:
                        break;
                    default:
                        string errorMsg = $"远程服务地址{requestUri}获取服务数据失败：" + resultObj.errors;
                        LoggerHelper.Current.Error(errorMsg);
                        throw new DataRequestException(errorMsg);
                }

            }
            LoggerHelper.Current.Info($"获取服务数据成功：{url}");
            return resultObj;
        }

        #endregion

        #region post
        /// <summary>
        /// 普通的post请求。body里没有东西。一般对应Create的接口
        /// </summary>
        /// <typeparam name="T">对应server端，Get接口返回的数据格式</typeparam>
        /// <param name="requestUri"></param>
        /// <param name="paramObj"></param>
        /// <param name="getUrl"></param>
        /// <returns></returns>
        /// <exception cref="DataRequestException"></exception>
        protected async Task<RESTfulResult<T>> PostAsync<T>(string requestUri, object paramObj = null, Func<string> getUrl = null)
        {
            var url = GetHttpUrl(requestUri, paramObj, getUrl);
            using var client = HttpClientFactory.Create();
            client.Timeout = TimeSpan.FromSeconds(timeOut);
            OnInitAuthorizationCode(client);
            var response = await client.PostAsync(url, null);
            if (response.StatusCode != HttpStatusCode.OK)
            {
                string errorMsg = $"远程服务地址{requestUri}获取服务数据失败, 返回代码：" + response.StatusCode;
                LoggerHelper.Current.Error(errorMsg);
                throw new DataRequestException(errorMsg); //这里是http网络请求本身的错误
            }
            var result = await response.Content.ReadAsStringAsync();
            var resultObj = JsonConvert.DeserializeObject<RESTfulResult<T>>(result);
            if (!resultObj.succeeded)
            {
                switch (resultObj.statusCode)
                {
                    case 400://后端 throw OOps.Bah
                    case 500://后端 throw OOps.Oh
                             //这里是furion框架下的错误。本质上是业务码 
                        break;
                    default:
                        string errorMsg = $"远程服务地址{requestUri}获取服务数据失败：" + resultObj.errors;
                        LoggerHelper.Current.Error(errorMsg);
                        throw new DataRequestException(errorMsg);
                }

            }
            LoggerHelper.Current.Info($"获取服务数据成功：{url}");
            return resultObj;

        }
        #endregion post
        #region PostFormAsync
        /// <summary>
        /// 向远程服务器POST数据，对应[FromForm]
        /// </summary>
        /// <typeparam name="T0">响应后的返回数据。</typeparam>
        /// <typeparam name="T1">POST数据类型。</typeparam>
        /// <param name="requestUri">远程服务器URL。</param>
        /// <param name="content">POST数据对象</param>
        /// <returns>返回远程服务器数据结果。</returns>
        protected async Task<RESTfulResult<T0>> PostFormAsync<T0, T1>(string requestUri, T1 content)
           where T0 : class, new()
           where T1 : class, new() => await PostFormAsync<T0, T1>(requestUri, content, null);

        /// <summary>
        /// 向远程服务器POST数据，对应[FromForm]
        /// </summary>
        /// <typeparam name="T0">响应后的返回数据。</typeparam>
        /// <typeparam name="T1">POST数据类型。</typeparam>
        /// <param name="requestUri">远程服务器URL。</param>
        /// <param name="content">POST数据对象</param>
        /// <param name="init">初始化RequesHeader</param>
        /// <returns>返回远程服务器数据结果。</returns>
        protected async Task<RESTfulResult<T0>> PostFormAsync<T0, T1>(string requestUri, T1 content, string contentType = "application/json")
            where T0 : class, new()
            where T1 : class, new()
        {
            var requestContent = CreatePostFormContent(content);
            return await PostFormAsyncCore<T0>(requestUri, requestContent, contentType);
        }

        /// <summary>
        /// 向远程服务器POST数据，对应[FromForm]
        /// </summary>
        /// <typeparam name="T">响应后的返回数据。</typeparam>
        /// <param name="requestUri">远程服务器URL。</param>
        /// <param name="content">POST数据对象</param>
        /// <param name="init">初始化RequesHeader</param>
        /// <returns>返回远程服务器数据结果。</returns>
        protected async Task<RESTfulResult<T>> PostFormAsyncCore<T>(string requestUri, HttpContent content, string contentType = "application/json")
        where T : class, new()
        {
            var url = ServerUrl.CombineUrlPath(requestUri);

            using var client = HttpClientFactory.Create();
            client.Timeout = TimeSpan.FromSeconds(timeOut);
            OnInitAuthorizationCode(client);
            OnInitRequestHeader(client, contentType);
            var response = await client.PostAsync(url, content);
            if (response.StatusCode != HttpStatusCode.OK)
            {
                string errorMsg = $"远程服务地址{requestUri}发送服务数据失败, 返回代码：" + response.StatusCode;
                LoggerHelper.Current.Error(errorMsg);
                throw new DataRequestException(errorMsg);
            }
            response.EnsureSuccessStatusCode();
            string result = await response.Content.ReadAsStringAsync();

            var resultObj = JsonConvert.DeserializeObject<RESTfulResult<T>>(result);
            if (!resultObj.succeeded)
            {
                string errorMsg = $"远程服务地址{requestUri}发送服务数据失败：" + resultObj.errors;
                LoggerHelper.Current.Error(errorMsg);
                throw new DataRequestException(errorMsg);
            }
            LoggerHelper.Current.Info($"发送服务数据成功：{url}");
            return resultObj;
        }
        #endregion

        #region PostBodyAsync

        /// <summary>
        /// 向远程服务器POST数据，数据T1放在body里。一般是Create
        /// </summary>
        /// <typeparam name="T0">响应后的返回数据的类型</typeparam>
        /// <typeparam name="T1">POST数据对象的类型</typeparam>
        /// <param name="requestUri">远程服务器URL</param>
        /// <param name="postObj">POST数据对象</param>
        /// <returns>返回远程服务器数据结果。.data可以得到内容</returns>
        /// <exception cref="DataRequestException"></exception>
        protected async Task<RESTfulResult<T0>> PostBodyAsync<T0, T1>(string requestUri, T1 postObj)
        {
            string contentType = "application/json";
            var url = ServerUrl.CombineUrlPath(requestUri);

            string strContent = postObj != null ? JsonConvert.SerializeObject(postObj) : "";
            var content = new StringContent(strContent, Encoding.UTF8, contentType);

            using var client = HttpClientFactory.Create();
            client.Timeout = TimeSpan.FromSeconds(timeOut);
            OnInitAuthorizationCode(client);
            OnInitRequestHeader(client, contentType);
            var response = await client.PostAsync(url, content);
            if (response.StatusCode != HttpStatusCode.OK)
            {
                string errorMsg = $"远程服务地址{requestUri}发送服务数据失败, 返回代码：" + response.StatusCode;
                LoggerHelper.Current.Error(errorMsg);
                throw new DataRequestException(errorMsg);
            }
            response.EnsureSuccessStatusCode();
            string result = await response.Content.ReadAsStringAsync();

            var resultObj = JsonConvert.DeserializeObject<RESTfulResult<T0>>(result);
            if (!resultObj.succeeded)
            {
                switch (resultObj.statusCode)
                {
                    case 400:
                    case 500:
                        break;
                    default:
                        string errorMsg = $"远程服务地址{requestUri}发送服务数据失败：" + resultObj.errors;
                        LoggerHelper.Current.Error(errorMsg);
                        throw new DataRequestException(errorMsg);
                }

            }
            LoggerHelper.Current.Info($"发送服务数据成功：{url}");
            return resultObj;
        }


        /// <summary>
        /// 向远程服务器POST数据。数据T放在body里。server端必须要返回<see cref="FileContentResultBaseString"/>
        /// </summary>
        /// <typeparam name="T">body里的类型</typeparam>
        /// <param name="requestUri"></param>
        /// <param name="postObj"></param>
        /// <returns>在wpf处，转为一个包含stream的result</returns>
        /// <exception cref="DataRequestException"></exception>
        protected async Task<RESTfulResult<Stream>> PostBodyStreamAsync<T>(string requestUri, T postObj)
        {
            string contentType = "application/json";
            var url = ServerUrl.CombineUrlPath(requestUri);

            string strContent = postObj != null ? JsonConvert.SerializeObject(postObj) : "";
            var content = new StringContent(strContent, Encoding.UTF8, contentType);

            using var client = HttpClientFactory.Create();
            client.Timeout = TimeSpan.FromSeconds(timeOut);
            OnInitAuthorizationCode(client);
            OnInitRequestHeader(client, contentType);
            var response = await client.PostAsync(url, content);
            if (response.StatusCode != HttpStatusCode.OK)
            {
                string errorMsg = $"远程服务地址{url}获取文件流服务失败, 返回代码：" + response.StatusCode;
                LoggerHelper.Current.Error(errorMsg);
                throw new DataRequestException(errorMsg);
            }
            response.EnsureSuccessStatusCode();
            var jsonStr = await response.Content.ReadAsStringAsync();
            var result = JsonConvert.DeserializeObject<RESTfulResult<FileContentResultBaseString>>(jsonStr);
            if (result.succeeded)
            {
                var bytes = Convert.FromBase64String(result.data.Data);
                var ms = new MemoryStream(bytes);
                return new RESTfulResult<Stream> { data = ms, succeeded = true };
            }
            var rr = new RESTfulResult<Stream> { succeeded = result.succeeded, errors = result.errors ?? "" };
            LoggerHelper.Current.Error($"远程服务地址{url}获取文件流服务失败, 返回信息：{rr.errors}");
            return rr;
        }

        #endregion


        #region delete

        /// <summary>
        /// 向远程服务器DELETE数据
        /// </summary>
        /// <typeparam name="T0">响应后的返回数据。</typeparam>
        /// <param name="requestUri">远程服务器URL。</param>
        /// <param name="content">POST数据对象</param>
        /// <param name="init">初始化RequesHeader</param>
        /// <returns>返回远程服务器数据结果。</returns>
        protected async Task<RESTfulResult<T0>> DeleteAsync<T0>(string requestUri)
        {
            string contentType = "application/json";
            var url = ServerUrl.CombineUrlPath(requestUri);


            using var client = HttpClientFactory.Create();
            client.Timeout = TimeSpan.FromSeconds(timeOut);
            OnInitAuthorizationCode(client);
            OnInitRequestHeader(client, contentType);
            var response = await client.DeleteAsync(url);
            if (response.StatusCode != HttpStatusCode.OK)
            {
                string errorMsg = $"远程服务地址{requestUri}发送服务数据失败, 返回代码：" + response.StatusCode;
                LoggerHelper.Current.Error(errorMsg);
                throw new DataRequestException(errorMsg);
            }
            response.EnsureSuccessStatusCode();
            string result = await response.Content.ReadAsStringAsync();

            var resultObj = JsonConvert.DeserializeObject<RESTfulResult<T0>>(result);
            if (!resultObj.succeeded)
            {
                string errorMsg = $"远程服务地址{requestUri}发送服务数据失败：" + resultObj.errors;
                LoggerHelper.Current.Error(errorMsg);
                throw new DataRequestException(errorMsg);
            }
            LoggerHelper.Current.Info($"发送服务数据成功：{url}");
            return resultObj;
        }
        #endregion

        #region PostFileAsync
        /// <summary>
        /// 向远程服务器上传文件。
        /// </summary>
        /// <param name="requestUri">远程服务器URL。</param>
        /// <param name="stream">文件流<see cref="Stream"/>对象。</param>
        /// <param name="fileName">上传的文件名。</param>
        /// <returns></returns>
        /// <exception cref="DataRequestException"></exception>
        protected async Task<bool> PostFileAsync(string requestUri, Stream stream, string fileName)
        {
            string contentType = "multipart/form-data";
            var url = ServerUrl.CombineUrlPath(requestUri);
            var streamContent = new StreamContent(stream, (int)stream.Length);
            streamContent.Headers.Add("Content-Type", "application/octet-stream");
            var content = new MultipartFormDataContent
            {
                { streamContent, "file", fileName }
            };
            using var client = HttpClientFactory.Create();
            client.Timeout = TimeSpan.FromSeconds(timeOut);
            OnInitAuthorizationCode(client);
            OnInitRequestHeader(client, contentType);
            var response = await client.PostAsync(url, content);
            if (response.StatusCode != HttpStatusCode.OK)
            {
                string errorMsg = $"远程服务地址{requestUri}发送文件服务失败, 返回代码：" + response.StatusCode;
                LoggerHelper.Current.Error(errorMsg);
                throw new DataRequestException(errorMsg);
            }
            response.EnsureSuccessStatusCode();
            var result = await response.Content.ReadAsStringAsync();
            var resultObj = JsonConvert.DeserializeObject<RESTfulResult<string>>(result);//实际server端有时候会是void
            if (!resultObj.succeeded)
            {
                string errorMsg = $"远程服务地址{requestUri}发送文件服务失败：" + resultObj.errors;
                LoggerHelper.Current.Error(errorMsg);
                throw new DataRequestException(errorMsg);
            }
            LoggerHelper.Current.Info($"发送文件服务成功：{url}");
            return resultObj.succeeded;
        }


        /// <summary>
        /// 向远程服务器上传文件。
        /// </summary>
        /// <typeparam name="TReturn">返回的类型。</typeparam>
        /// <param name="requestUri"></param>
        /// <param name="files">文件数组</param>
        /// <returns></returns>
        /// <exception cref="DataRequestException"></exception>
        protected async Task<RESTfulResult<TReturn>> PostFileAsync<TReturn>(string requestUri, List<NetworkFileInfo> files)
        {
            string contentType = "multipart/form-data";
            var url = ServerUrl.CombineUrlPath(requestUri);
            var content = new MultipartFormDataContent();
            for (int i = 0; i < files.Count; i++)
            {
                var byteContent = new ByteArrayContent(files[i].Data, 0, files[i].Data.Length);
                byteContent.Headers.Add("Content-Type", "application/octet-stream");
                content.Add(byteContent, "file" + i.ToString(), files[i].FileName);
            }
            using var client = HttpClientFactory.Create();
            client.Timeout = TimeSpan.FromSeconds(timeOut);
            OnInitAuthorizationCode(client);
            OnInitRequestHeader(client, contentType);

            var response = await client.PostAsync(url, content);
            if (response.StatusCode != HttpStatusCode.OK)
            {
                string errorMsg = $"远程服务地址{requestUri}发送文件服务失败, 返回代码：" + response.StatusCode;
                LoggerHelper.Current.Error(errorMsg);
                throw new DataRequestException(errorMsg);
            }
            response.EnsureSuccessStatusCode();
            var result = await response.Content.ReadAsStringAsync();
            var resultObj = JsonConvert.DeserializeObject<RESTfulResult<TReturn>>(result);
            if (!resultObj.succeeded)
            {
                string errorMsg = $"远程服务地址{requestUri}发送文件服务失败：" + resultObj.errors;
                LoggerHelper.Current.Error(errorMsg);
                throw new DataRequestException(errorMsg);
            }
            LoggerHelper.Current.Info($"发送文件服务成功：{url}");
            return resultObj;
        }

        /// <summary>
        /// 向远程服务器上传文件。
        /// </summary>
        /// <param name="requestUri">远程服务器URL。</param>
        /// <param name="files">上传的文件名数组。</param>
        /// <returns></returns>
        protected async Task<RESTfulResult<Stream>> PostFileExtAsync(string requestUri, List<NetworkFileInfo> files)
        {
            string contentType = "multipart/form-data";
            var url = ServerUrl.CombineUrlPath(requestUri);
            var content = new MultipartFormDataContent();
            for (int i = 0; i < files.Count; i++)
            {
                var byteContent = new ByteArrayContent(files[i].Data, 0, files[i].Data.Length);
                byteContent.Headers.Add("Content-Type", "application/octet-stream");
                content.Add(byteContent, "file" + i.ToString(), files[i].FileName);
            }
            using var client = HttpClientFactory.Create();
            client.Timeout = TimeSpan.FromSeconds(timeOut);
            OnInitAuthorizationCode(client);
            OnInitRequestHeader(client, contentType);

            var response = await client.PostAsync(url, content);
            if (response.StatusCode != HttpStatusCode.OK)
            {
                string errorMsg = $"远程服务地址{requestUri}发送文件服务失败, 返回代码：" + response.StatusCode;
                LoggerHelper.Current.Error(errorMsg);
                throw new DataRequestException(errorMsg);
            }
            response.EnsureSuccessStatusCode();
            var jsonStr = await response.Content.ReadAsStringAsync();
            var result = JsonConvert.DeserializeObject<RESTfulResult<FileContentResultBaseString>>(jsonStr);
            if (result.succeeded)
            {
                var bytes = Convert.FromBase64String(result.data.Data);
                var ms = new MemoryStream(bytes);
                return new RESTfulResult<Stream> { data = ms, succeeded = true };
            }
            var rr = new RESTfulResult<Stream> { succeeded = result.succeeded, errors = result.errors ?? "" };
            LoggerHelper.Current.Error($"远程服务地址{url}获取文件流服务失败, 返回信息：{rr.errors}");
            return rr;
        }
        #endregion

        #region Other
        /// <summary>
        /// 将实体对象转换为Form集合。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        protected FormUrlEncodedContent CreatePostFormContent<T>(T obj) where T : class, new()
        {
            var props = Reflect.GetPropertys<T>(BindingFlags.Public | BindingFlags.Instance);
            if (props == null) return null;

            var keyValuePairs = new List<KeyValuePair<string, string>>();
            foreach (var prop in props)
            {
                var val = prop.GetValue(obj);
                keyValuePairs.Add(new KeyValuePair<string, string>(prop.Name, val.IsNullOrEmpty() ? "" : val.ToString()));
            }
            var content = new FormUrlEncodedContent(keyValuePairs);
            return content;
        }


        /// <summary>
        /// 获取指定方法的API HttpGet URL地址字符串。
        /// </summary>
        /// <param name="requestUri">API方法名。</param>
        /// <param name="paramObj">参数信息。</param>
        /// <returns></returns>
        protected virtual string GetHttpUrl(string requestUri, object paramObj = null, Func<string> getUrl = null)
        {
            ServerUrl = GlobalObject.CurrentConfig.ServerAddress;
            string url = ServerUrl.CombineUrlPath(requestUri);
            if (getUrl != null)
            {
                string getUrlStr = getUrl();
                url = getUrlStr.CombineUrlPath(requestUri);
            }

            if (string.IsNullOrEmpty(url))
            {
                throw new NullReferenceException("调用前请初始化_baseUrl值。");
            }
            if (paramObj == null)
            {
                return url;
            }

            PropertyInfo[] propertyInfos = Reflect.GetPropertys(paramObj.GetType());

            for (int i = 0; i < propertyInfos.Length; i++)
            {
                object value = propertyInfos[i].GetValue(paramObj);
                string pre = i == 0 ? "?" : "&";
                url += (pre + propertyInfos[i].Name + "=" + (value != null ? value.ToString() : ""));
            }
            return url;
        }

        /// <summary>
        /// 32位MD5加密
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        protected string Md5Hash(string input)
        {
            MD5 md5 = MD5.Create();
            byte[] data = md5.ComputeHash(Encoding.Default.GetBytes(input));
            StringBuilder sBuilder = new StringBuilder();
            for (int i = 0; i < data.Length; i++)
            {
                sBuilder.Append(data[i].ToString("x2"));
            }
            return sBuilder.ToString();
        }
        #endregion
    }
}
